package com.woniuxy.shiro;

import org.apache.shiro.mgt.SessionStorageEvaluator;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSessionStorageEvaluator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author：向天浩
 * @Date：2022/2/23 18:49
 * @Description :;shiro的核心配置类
 */
//有这个注解才能自定义类注册到spring
@Configuration
public class ShiroConfig {

    //配置securityManager，因为我们要自定义JWT方式进行认证！
    // 把自定义域交给securityManager来进行管理和使用！因为是web项目，所以使用DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager securityManager(MyRealm realm){
        //使用下面的方法是为了处理底层无法识别我们自定义的MyJwtToken
        realm.setAuthenticationTokenClass(MyJwtToken.class);
        //securityManager这个是一个全局管理者，内部由各个组件构成，每个组件负责各自的功能
        return new DefaultWebSecurityManager(realm);
    }
    @Bean
    //配置过滤器工厂,使我们自定义的过滤器生效，以及过滤条件和拦截url
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        //创建过滤器工厂
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //创建一个map,参数是string和filter它来自javax.servlet.Filter;这个包
        Map<String, Filter> filters = new HashMap<>();
        //将我们自定义的过滤器放入这个map
        filters.put("JWT",new JwtFilter());
        //把我们写的filter放入shiro的过滤器工厂bean中，然后交给spring来管理！
        shiroFilterFactoryBean.setFilters(filters);

        //setFilterChainDefinitionMap需要map参数
        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        //过滤器从下往下执行
        filterChainDefinitionMap.put("/**","JWT");//所有请求都经过我自定义的"JWT"过滤器
 //       filterChainDefinitionMap.put("/rbac/**","authc");//这个的意思是这个rbac路径的所有请求都需要经过认证
        filterChainDefinitionMap.put("/login","anon");//这个的意思是login登录请求的url被放行，登录是不需要认证的(anon是匿名访问，他是shiro底层自己的过滤器)
        filterChainDefinitionMap.put("/401","anon");//这个的意思是我们的错误页面也是需要放行的，错误页面不需要认证


        //设置过滤器链；FilterChain 我们所有的权限框架都是基于一堆过滤器链来实现的！
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;

    }

    /**
     * 禁用session, 不保存用户登录状态。保证每次请求都重新认证。
     * 需要注意的是，如果用户代码里调用Subject.getSession()还是可以用session
     */
    @Bean
    protected SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }
    //开启shiro注解支持
    @Bean
    public AuthorizationAttributeSourceAdvisor
    authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new
                AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    /**
     * Description : 管理Subject主体对象,生命周期的组件,用户只是打印下生产销毁日志什么的,请参考spring中bean的生命周期   <br/>
     * ChangeLog : 1. 创建 (2021/4/27 0:25 [mayuhang]);
     *
     * @return org.apache.shiro.spring.LifecycleBeanPostProcessor
     **/
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }
}
